package org.flyan.ffsm.core.sm;

import org.flyan.ffsm.core.event.Event;
import org.flyan.ffsm.core.state.State;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

/**
 * 有限状态机创建者
 *
 * @param <ST> 状态标志
 * @param <ET> 事件标志
 * @author flyan
 * @version 1.0
 * @date 6/28/22
 */
public class StateMachineBuilder<ST, ET>
        implements Builder<StateMachine<ST, ET>>, Serializable {

    private static final long serialVersionUID = -787347886329773210L;
    private final StateMachine<ST, ET> machine;

    public StateMachineBuilder(StateMachine<ST, ET> machine) {
        this.machine = machine;
    }

    public StateMachineBuilder<ST, ET> state(State<ST, ET> state) {
        machine.registerState(state);
        return this;
    }

    @SafeVarargs
    public final StateMachineBuilder<ST, ET> states(State<ST, ET>... states) {
        Arrays.stream(states).forEach(machine::registerState);
        return this;
    }

    public StateMachineBuilder<ST, ET> event(ST stateTag, Event<ST, ET> event) {
        machine.registerEvent(stateTag, event);
        return this;
    }

    public StateMachineBuilder<ST, ET> event(State<ST, ET> state, Event<ST, ET> event) {
        machine.registerEvent(state, event);
        return this;
    }

    /**
     * 注册多个事件，这些事件依赖于一个状态
     */
    @SafeVarargs
    public final StateMachineBuilder<ST, ET> events(State<ST, ET> state, Event<ST, ET>... events) {
        machine.registerState(state);
        Arrays.stream(events).forEach(event -> machine.registerEvent(state, event));
        return this;
    }

    /**
     * 注册多个事件，这些事件依赖于一个状态
     */
    public StateMachineBuilder<ST, ET> events(State<ST, ET> state, List<Event<ST, ET>> events) {
        machine.registerState(state);
        events.forEach(event -> machine.registerEvent(state, event));
        return this;
    }

    public StateMachine<ST, ET> build() {
        return machine;
    }

    public static <ST, ET> StateMachineBuilder<ST, ET> builder() {
        return builder(new StateMachine<>());
    }

    public static <ST, ET> StateMachineBuilder<ST, ET> builder(StateMachine<ST, ET> machine) {
        return new StateMachineBuilder<>(machine);
    }

}
